//27/12/17  RAFAEL RIBEAUX
//0.21e Motor grfico capaz de manejar 1 efecto de 7x60 bits en forma de bucle

/// BLOQUE DE CONFIGURACION DEL MICROCONTROLADOR
#include <16F628a.h>
//#include <16F648a.h>
//#include <16F88.h>

#FUSES WDT                    //Watch Dog Timer
#FUSES PUT					//Power Up time habilitado
#FUSES MCLR                   //NO Master Clear pin used for I/O
#FUSES NOBROWNOUT                  //
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOPROTECT			//Proteccion del codigo
#FUSES INTRC	
#FUSES NOCPD                // EEPROM desprotegida para poder leer el codigo ID
/* 16f88:*/
// #FUSES NOWRT 
// #FUSES NODEBUG
// #FUSES CCPB0
// #FUSES NOFCMEN
// #FUSES NOIESO

#use delay(clock=4000000)
#use fast_io(A)
#use fast_io(B)
//#use fixed_io(a_outputs=PIN_A0, PIN_A1, PIN_A6, PIN_A7)
//#use fixed_io(a_outputs=PIN_A0, PIN_A1, PIN_A7)
//#use fixed_io(b_outputs=PIN_B2, PIN_B4, PIN_B5, PIN_B6, PIN_B7)

#define led1 PIN_A1
#define led2 PIN_A0
#define led3 PIN_A7
#define led4 PIN_B7
#define led5 PIN_B6
#define led6 PIN_B5
#define led7 PIN_B4

#define fase1 PIN_B2	//fases de control de energ'ia
#define fase2 PIN_A1	//fases de control de energ'ia

#bit TRISB_0 = 0x86.5   //Habilitacion de interrupcion por RB 
#bit TRISB_1 = 0x186.5   //Habilitacion de interrupcion por RB 

#bit RBIF_0 = 0x0B.0   //Bandera de interrupcion por RB 
#bit RBIF_1 = 0x8B.0   //Bandera de interrupcion por RB 
#bit RBIF_2 = 0x10B.0   //Bandera de interrupcion por RB 
#bit RBIF_3 = 0x18B.0   //Bandera de interrupcion por RB 

#bit PORTB_0 = 0x06.4   //Habilitacion de interrupcion por RB 
#bit PORTB_1 = 0x106.4   //Habilitacion de interrupcion por RB 

#bit CCP1IF = 0x0C.2   //Habilitacion de interrupcion por RB 

#byte TRISA = 0x85   //Configuracion del registro TRISA



/*EFECTOS GUARDADOS EN LA EEPROM*/
#rom  0x2100={79,65,65,121,121,121,65,65,79,79,65,65,121,121,121,65,65,79, // castillo invertido
              63,61,57,51,7,7,15,31,31,63,61,57,51,7,7,15,31,31,   // aspa invertida
              8,28,62,127,28,28,28,0,127,119,99,65,0,99,99,99,127,0,  //  flecha en contraste
              96,120,78,67,78,120,96,120,78,67,78,120,96,120,78,67,78,120,	// 3 Podios
              99,85,73,65,65,65,73,85,99,99,85,73,65,65,65,73,85,99,	// circulitos
              97,81,73,69,67,69,73,81,97,97,81,73,69,67,69,73,81,97,	// Triangulitos entre rayas
              64,96,96,112,120,120,108,70,66,64,96,96,112,120,120,108,70,66, //aspa doble 18 vet x 4
			  0,1} //ID EQUIPO: Equipo con numero ID # 1

/// BLOQUE DE DEFINICION DE VARIABLES GLOBALES

///VARIABLES DE CONFIGURACI'ON DEL EQUIPO/////////////////////////////////////////////
/// VARIABLES DEL MOTOR DE AUTOESTABILIZACION (CONFIGURACION)
long long const Valmax_Tim1_uS = 983040;      ///Valor maximo de tiempo en uS que debe haber contado el timer 1 para que cumpla con el tiempo minimo de una vuelta (Tmep) , en este caso para X Hz, 60 CP y 8Mhz el reloj del PIC
long const Valmin_Tim1_uS = 55556;
long const Valmin_Tim2 = 771;             ///Valor minimo de tiempo en uS que debe haber contado el timer 1 para que cumpla con el tiempo maximo de una vuelta (Tmep) , en este caso para 10Hz, 60 CP y 8Mhz el reloj del PIC
long const Valmax_Tim2 = 14336;
int const vector_max = 72 ;            ///Variable que contiene la cantidad de vectores de la pantalla POV
int const Tcm = 1;                           /// 1 uS que es igual a 4MHz/4 1/ (Fosc/4) 

/// VARIABLES DEL MOTOR DE GREAFICADO (CONFIGURACION)
int const cantidad_efectos_max = 7; //variable que contiene el numero de efectos "normales" en el equipo
long const repeticiones_efectos_max = 1; //variable que contiene la cantidad de veces que se van a repetir los efectos

short buffer1_display[7][18] = {0}; 
short buffer2_display[7][18] = {0}; 
int buffer_binario[7] = {0};  
int const size_efectos[7] = {18,18,18,18,18,18,18};   //arreglo que almacena el tamao de los arreglos
int const direccion_efecto[7] = {0,18,36,54,72,90,108};   //Direcciones de los efectos en la EEPROM

/// VARIABLES DEL MOTOR DE AUTOESTABILIZACION//////////////////
// int Tg = 0;                            ///Variable que contiene el valor del tiempo de graficado
long long Acum_Tim1 = 0;               ///Valor que va acumulando el timer 1 cada vez que se lee para determinar el valor Tg (tiempo de 1 vuelta)
// long long const Valmax_Tim1 = 983040;      ///Valor maximo de tiempo en uS que debe haber contado el timer 1 para que cumpla con el tiempo minimo de una vuelta (Tmep) , en este caso para X Hz, 60 CP y 8Mhz el reloj del PIC
// int const Valmin_Tim1 = 768;             ///Valor minimo de tiempo en uS que debe haber contado el timer 1 para que cumpla con el tiempo maximo de una vuelta (Tmep) , en este caso para 10Hz, 60 CP y 8Mhz el reloj del PIC
long T1_temp = 0;                     ///Valor temporal para calcular Acum_Tim1
long T2_temp = 0;                     ///Valor temporal para calcular Acum_Tim1 
int modo = 0;                        ///modo de trabajo en el que el PIC no muestra informacion grafica    (es una variable tipo short)
short primera_ejecucion = 1;                  ///Variable bandera que indica que estamos en una primera ejecucion del modulo CCP (es una variable tipo short)
short timer2_on = 0;                     ///Variable bandera que indca 1 si se esta ejecutando la interrupcion por timer2
// int const vector_max = 60 ;            ///Variable que contiene la cantidad de vectores de la pantalla POV
int vtemp0 = 0;                     ///Variable temporal
long Tg_sin_ajuste = 0;                  ///Variable temporal 2
int Tg_ajustado_temp = 0;                   ///Variable temporal de Tg, que contiene el valor precalculado en segundo plano
// int postscaler_timer2 = 1;               ///variable usada en la configuraci'on del timer 2
int datos_ok = 0;               ///Variable que indica que los datos de calculo estan listos
long long Acum_Tim1_uS = 0;               ///Variable que guarda el valor acumulado de una vuelta en uS
short CCP1_on = 0;                        ///Variable bandera que indica si estamos o no en una interrupcion por CCP1
int prescaler_timer2_temp = 1;               ///Variable temporal que almacena el valor del prescaler del timer2
int postscaler_timer2_temp = 1;               ///Variable temporal que almacena el valor del postscaler del timer2
//int indice_timer2 = 0;                     ///
// int const Tcm = 1;                           /// 0,5 uS que es igual a X/2
int contador_pulsos = 0;                  ///variable temporal     
int contador_ciclo = 0;                   //valor por defecto
short lectura_on = 0;                  //variable bandera, de sincronizaci'on de la funci'on lectura_timer1 /esta variable es short
short colision_CCP = 0;                //variable bandera, de sincronizacion de CCP1 con lectura_timer1  /esta variable es short
short const coef_correccion = 1;        // coeficiente usado para corregir el "error de vector final". 


/// VARIABLES DEL MOTOR DE GREAFICADO
int num_efecto = 0;         //N'umero de la posici'on del efecto que se va a graficar (o que se esta graficando)
// int const cantidad_efectos_max = 7; //variable que contiene el numero de efectos "normales" en el equipo
//int valor_efecto_cargar = 0;      //variable que contiene el valor del efecto a graficar
int columna_carga_codigo = 0;      //Indica la columna que se va a cargar en la decodificaci'on y carga
// int fila_buffer1 = 0;            //Columna del 
// int vtemp1 = 0;
// int seguidor0 = 0;
//int seguidor1 = 0;
int columna_graficado = 0;   //Numero de la columna a graficar
int size_efecto = 0;	       //variable que contiene el tamao del efecto a graficar
long repeticiones_efecto = 0; //Variable contador que contiene el valor de la repeticion
// long const repeticiones_efectos_max = 100; //variable que contiene la cantidad de veces que se van a repetir los efectos
short cambio_efecto = 0;   //variable bandera que indica cuando hay que cargar el pr'oximo efecto
int estado_buffer1 = 1;      //variable bandera que monitorea el estado del buffer1
int estado_buffer2 = 1;      //variable bandera que monitorea el estado del buffer2
short buffer_carga_on = 0;   //Variable que indica el buffer que debe cargarse
short buffer_graficado_on = 0;   //Variable que indica el desde que buffer graficar
short carga_graficado_on = 0;    //variable que indica que se esta ejecutando el bloque de carga y graficado para el algoritmo anticolision
short anticolision_timer2 = 0;   //variable que indica que hubo una colision de timer2 con el bloque de carga y graficado
int sincronizacion_ciclo = 0; //variable que indica cuando se debe verificar un ciclo
                
/// VARIABLES DEL BOTON ON/OFF y SLEEP
//short on_off = 1; //0 off, 1 on, por defecto el equipo esta en on
int estado_sleep = 0;

///Variables del modulo de detecci'on de bajo voltaje (modulos comparador y voltaje referencia)
//int estado_comparador = 0;   //variable short que indica si el comparador est'a encendido o apagado
int apagado_completo = 0;   //variable que indica que el equipo esta apagado por bajo voltaje y que debe recargarse antes de volverlo a usar

///Variable para controlar el watchdog
short watchdog_awake = 0;   //Variable bandera que indica si se despert'o el PIC por el watchdog, en caso positivo, vale 1.

                     
///BLOQUE DE PROTOTIPOS DE FUNCIONES
///Prototipos de Funciones del motor de autoestabilizacion
long calculo_tg();
void lectura_timer1();
short verificar_ciclo();
void reset_variables_tim1();
void anticolision();

///Prototipos de Funciones del motor de graficado
void cargar_buffer(int, short);
void decimal_binario(int);
void graficar(int, short);
void seccion_carga(void);

///Prototipos de funciones Atencion al boton y SLEEP
void efectos_simples(void);
void all_leds_off(void);
void reset_variables_sleep(void);
void carga_inicial(void);
void preparacion_sleep(void);
void on_off_timer1(short);

///Prototipos de funciones del modulo de detecci'on de bajo voltaje (modulos comparador y voltaje referencia)
void on_off_voltaje(short);

///Prototipos de funciones de atencion al watchdog
void comprobacion_awake(void);
//void comprobacion_encendido(void);


/// BLOQUE DE DEFINICION DE FUNCIONES 2 (Funciones con prototipos)
///Funciones del motor de graficado////////////////////////////////////////////////////////////////

void seccion_carga(void)
{
   
   if(num_efecto <= (cantidad_efectos_max - 2))  //Cambiar al prximo efecto 
      num_efecto++;
   else if(num_efecto <= (cantidad_efectos_max - 1))
       num_efecto = 0;

   if(((estado_buffer1 == 0)||(estado_buffer1 == 1))&& ((estado_buffer2 == 3)||(estado_buffer2 == 4)))
      buffer_carga_on = 0;
   else if(((estado_buffer2 == 0)||(estado_buffer2 == 1))&& ((estado_buffer1 == 3)||(estado_buffer1 == 4)))
      buffer_carga_on = 1;
   
   cargar_buffer(num_efecto, buffer_carga_on);
}

void graficar(int columna_buffer_display_local, short buffer_graficado_on)
/*Esta funcion es la que escribe el buffer en los leds
la entrada es el buffer, 1 para el buffer CCP
2 para el buffer del timer2
*/
{
  if(buffer_graficado_on == 0)
  {
      output_bit(led1, buffer1_display[0][columna_buffer_display_local]);
      output_bit(led2, buffer1_display[1][columna_buffer_display_local]);
      output_bit(led3, buffer1_display[2][columna_buffer_display_local]);
      output_bit(led4, buffer1_display[3][columna_buffer_display_local]);
      output_bit(led5, buffer1_display[4][columna_buffer_display_local]);
      output_bit(led6, buffer1_display[5][columna_buffer_display_local]);
      output_bit(led7, buffer1_display[6][columna_buffer_display_local]);
  }
  else
  {
      output_bit(led1, buffer2_display[0][columna_buffer_display_local]);
      output_bit(led2, buffer2_display[1][columna_buffer_display_local]);
      output_bit(led3, buffer2_display[2][columna_buffer_display_local]);
      output_bit(led4, buffer2_display[3][columna_buffer_display_local]);
      output_bit(led5, buffer2_display[4][columna_buffer_display_local]);
      output_bit(led6, buffer2_display[5][columna_buffer_display_local]);
      output_bit(led7, buffer2_display[6][columna_buffer_display_local]);
  }
  /*actualizaci'on del estado de graficado*/
  if(buffer_graficado_on == 0)
   estado_buffer1 = 4;   //Indica que se est'a graficando desde el buffer1
  else
   estado_buffer2 = 4;   //Indica que se est'a graficando desde el buffer2
}

void cargar_buffer(int num_efecto_local,short buffer_carga_on_local)
/* La variable num_efecto_local contiene la posicin del efecto que se va a graficar ().
El n'umero del efecto en si lo contiene el valor de dicha posici'on en direccion_efecto que apunta a la EEPROM
*/
{
   int columna_cargar = 0;   //Numero de la columna a cargar en el buffer de graficado
   int columna_carga_codigo = 0;      //Indica la columna que se va a cargar en la decodificaci'on y carga
   int fila_buffer1 = 0;            //Columna del 
   int vtemp1 = 0;	//variable de asignaci'on temporal
  // int seguidor0 = 0;
   
       /*actualizaci'on del estado de graficado*/
  if(buffer_carga_on == 0)
   estado_buffer1 = 2;   //Indica que se est'a graficando desde el buffer1
  else
   estado_buffer2 = 2;   //Indica que se est'a graficando desde el buffer2

    for(columna_carga_codigo = (direccion_efecto[num_efecto]); columna_carga_codigo <= ((direccion_efecto[num_efecto]) + ((size_efectos[num_efecto_local]) - 1)); columna_carga_codigo++)
   {
      vtemp1 = read_eeprom(columna_carga_codigo);
      decimal_binario(vtemp1);   // valor optimizado 
      //decimal_binario(read_eeprom(columna_carga_codigo));   // valor optimizado ++
      
      for(fila_buffer1 = 0; fila_buffer1 <= 6; fila_buffer1++)
      {
        if(buffer_carga_on_local == 0)
      {
            buffer1_display[fila_buffer1][columna_cargar] = buffer_binario[fila_buffer1];
         //seguidor0 = buffer_binario[fila_buffer1]; 
      }
         else
            buffer2_display[fila_buffer1][columna_cargar] = buffer_binario[fila_buffer1];
      }
     columna_cargar++;   //Coluna a cargar en el buffer_display, que es diferente a columna_carga_codigo
   }
    /*actualizaci'on del estado de graficado*/
  if(buffer_carga_on == 0)
   estado_buffer1 = 3;   //Indica que se est'a graficando desde el buffer1
  else
   estado_buffer2 = 3;   //Indica que se est'a graficando desde el buffer2
}

void decimal_binario(int decimal)   //esta funci'on solo llega hasta 7 bits, o el n'umero 128 en decimal
{
/*Versi'on corregida y final*/
   short val_binario = 0; 
   int contador = 0;
   int centinela1 = 64;
   int centinela2 = 191;
   
   for(contador = 6; contador >= 1; contador--)
   {
      if((decimal >= centinela1)&&(decimal <= (centinela2 - centinela1)))
      {
         if(decimal >= centinela1)
         val_binario = 1;
        else
         val_binario = 0;
         
         decimal = decimal - centinela1;
      }
      else 
         val_binario = 0;   //Con esta codigo se garantiza que siempre se escriba en el buffer_binario
         
      centinela1 = centinela1 / 2;
      centinela2 = centinela2 - centinela1;
      buffer_binario[contador] = val_binario;
      //seguidor0 = val_binario;  // variable de prueba

   }

   if(decimal == 1)
      val_binario = 1;
   else if(decimal == 0)
      val_binario = 0;
   
   buffer_binario[0] = val_binario; 
   //seguidor0 = val_binario;  // variable de prueba
}


///FUNCIONES DEL MOTOR DE AUTOESTABILIZACI'ON ///////////////////////////////////////////////////////
long calculo_tg()
{
    return (((Tg_sin_ajuste * Tcm) / prescaler_timer2_temp) / postscaler_timer2_temp ) - coef_correccion;
}

void lectura_timer1()
/*    Esta funcion se usa para  determinar el tiempo de una vuelta lo que hace es
leer  el timer 1 e ir acumulando su valor en el registro Acum_Tim1
tiene en cuenta si el timer 1 se desbordo!!! 
se tiene en cuenta si est'a o no en la interrupci'on por CCP1
donde termina el c'alculo de y la asignacion del tiempo acumulado a Acum_tim1_uS  */            
{
   lectura_on = 1;            //variable que indica que se est'a ejecutando la lectura del timer1
      
   if((contador_ciclo == 0)&&(CCP1_on == 1))               //Se verifica si estamos en el comienzo de una cadena de posibles ciclos 'utiles
      reset_variables_tim1();
   
   if(primera_ejecucion == 1) //El prop'osito de primera_ejecuci'on es asignar el primer valor del timer1 a T1_temp
                                      //en las sucesivas lecturas, timer1 se asigna a T2_temp
   {  
     if(CCP1_on == 1)                        //en caso que estemos en la interrupcion CCP1 se lee el registro CCP1 en vez del timer1
      T1_temp = CCP_1;                  //lectura del registro correspondiente a la interrupcion CCP1
     else
      T1_temp = get_timer1();                     //Lectura del timer1 en caso de que no estemos en la interrupci'on por CCP1
      
     primera_ejecucion = 0;                     //Se actualiza el valor de la variable primera_ejecucion 
   }
   else if(primera_ejecucion == 0)
   {
      if(CCP1_on == 1)                        //en caso que estemos en la interrupcion CCP1 se lee el registro CCP1 en vez del timer1
         T2_temp = CCP_1;                  //lectura del registro correspondiente a la interrupcion CCP1
      else
         T2_temp = get_timer1();                  ///Lectura del timer1
      
      if(T2_temp >= T1_temp)
         {
         Acum_Tim1 = (Acum_Tim1 + (T2_temp - T1_temp));   ///Se guarda el valor del timer 1
         }
      else if(T2_temp < T1_temp)
         {
         Acum_Tim1 = (Acum_Tim1 + ((65536 - T1_temp) + T2_temp));
         }

        T1_temp = T2_temp;                     ///Guarda el valor de T2 en T1 y dispone T2 para una nueva operacion
      T2_temp = 0;                        ///por razones de seguridad, T2_temp se lleva a cero
   }
   
   if(CCP1_on == 1)
   {
      /* Area de asignaci'on heredada de CCP1*/
      if(contador_ciclo <= 1)                  //Bloque de conteo de ciclo 'util
         contador_ciclo++;               //cuenta hasta  contador_ciclo == 2
   
   if(contador_ciclo == 2)
      Acum_Tim1_uS = Acum_Tim1 / Tcm; 
     
      //contador_pulsos = 0;         //variable de prueba
     Acum_Tim1 = 0;  
      colision_CCP = 0;
     ////////
	 sincronizacion_ciclo = 1;	//variable que indica qe se debe hacer una verificacion del ciclo
     CCP1_on = 0;
   }
   
   lectura_on = 0;   
}

void anticolision()
{
   if(CCP_1 > T1_temp) //
   {
      CCP1_on = 1;
   }
   else if(CCP_1 < T1_temp)
   {
      Acum_Tim1 = Acum_Tim1 - (T1_temp - CCP_1);
      T1_temp = CCP_1;
      CCP1_on = 1;
   }

}

short verificar_ciclo()
/* Esta funcion verifica si el ciclo entre las 2 interrupciones por CCP (valor Acum_tim1) esta en los valores adecuados para graficar y devuelve 
un 1 si los valores son adecuados para graficar y un 0 si esta fuera de rango para graficar
*/
{
   short x = 0;     ///Variable que contiene el estado del ciclo

	 if(modo == 1) //Para que no cambie de modo cuando el modo sea 1 y no se lean los bloques sucesivos de esta funcion
		x = 1;
		
   if((contador_ciclo == 2)&&(sincronizacion_ciclo == 1)) //este bloque se ejecuta luego de una interrupcion CCP valida y completada con la lectura del timer1
   {
      if(((Acum_Tim1_uS) >= Valmin_Tim1_uS) && ((Acum_Tim1_uS) <= Valmax_Tim1_uS)) //Filtro que define el Modo 1
         x = 1;  
	  else //if((Acum_Tim1_uS) < (Valmin_Tim1_uS))
	  {
		all_leds_off();	//se apagan todos los leds si se sale del filtro de graficado
		x = 0;	//se define el modo 0
	 }
 
      sincronizacion_ciclo = 0;	// se resetea la variable
   }
   
   if(Acum_Tim1 > Valmax_Tim1_uS) //Definici'on de Modo 0. Este caso tiene mayor prioridad que el anterior. Es para el caso en que se detenga el equipo o vaya lento y no se ejecute CCP1
      x = 0;                    
                                        
   return x;                     //Se devuelve el resultado de x
}

void reset_variables_tim1()
{
   Acum_Tim1 = 0;
   Acum_Tim1_uS = 0;
   T1_temp = 0;
   T2_temp = 0;
   primera_ejecucion = 1;
}

///Funciones de atencion a los botones y SLEEP ////////////////////////////////////////////////////////////////
void on_off_timer1(short bandera)
{
   if(bandera == 1)   //Encender timer1 y modulo CCP
   {
      setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);      //32,7 ms overflow
      setup_ccp1(CCP_CAPTURE_RE);
      enable_interrupts(INT_CCP1);
   }
   else
   {
      disable_interrupts(INT_CCP1);   //Desabilitado de la interrupci'on por CCP para que la misma no despierte al PIC
      setup_ccp1 (CCP_OFF);   //Apagado del m'odulo CCP1
      setup_timer_1 (T1_DISABLED);   //Apagar el m'odulo timer 1
   }
}

void preparacion_sleep(void)
/*Esta funcion va a preparar al PIC para el SLEEP si bandera es cero
y va a preparar la salida del PIC a su estado normal luego de salir del SLEEP si bandera es 1*/
{
      /* Bloque de preparaci'on del SLEEP en el modo sleep- */
     
      disable_interrupts(INT_TIMER2);   // desabilitar la interrupci'on por timer 2
      //SETUP_TIMER_2(T2_DISABLED); //Apagar el modulo timer 2
     all_leds_off();   //apagar todos los leds
     reset_variables_sleep();   //rsetear todas las variables antes del sleep
}

void carga_inicial(void)
/*esta funcion va a definir las condiciones iniciales despues de salir de un  sleep*/
{
   all_leds_off();                       //Se garantiza que todos los leds est'en apagados al iniciar el equipo
   num_efecto = 0;               //es redundante, solo con proposito visual (quitar mas adelante)
   cargar_buffer(num_efecto, buffer_carga_on); //(se carga el buffer1 por defecto)
   num_efecto++;            //Se apunta al segundo efecto
   buffer_carga_on = 1;      //se indica que cargue el buffer2   
   cargar_buffer(num_efecto, buffer_carga_on);
   size_efecto = (size_efectos[num_efecto] - 1);  //correcci'on del tamao de los efectos antes de graficar
}


void efectos_simples(void)
/*Esta funci'on es para reproducir los efectos de:
- encendido del equipo (luego de haberse apagado por el boton)
- apagado del equipo
-Atencion a los botones (modo, seleccion, etc)
*/
{
   restart_wdt();
   int contador_local = 0;
   
   for(contador_local = 0; contador_local <= 2; contador_local++)
    {
      output_high(led1);
      delay_ms(500);
      restart_wdt();
      output_low(led1);
      delay_ms(500);
      restart_wdt();
   }
}

void all_leds_off()
/*esta funci'on apaga o enciende todos los leds, si on_off_leds es cero, se apagan, si es 1 se encienden*/
{
      output_low(led1);
      output_low(led2);
      output_low(led3);
      output_low(led4);
      output_low(led5);
      output_low(led6);
      output_low(led7);
}

void reset_variables_sleep(void)
{
   reset_variables_tim1();   //se resetean todas las variables de graficado 
   contador_ciclo = 0;
   estado_buffer1 = 0;
   estado_buffer2 = 0;
   num_efecto = 0;
   buffer_carga_on = 0; 
   buffer_graficado_on = 0;
   carga_graficado_on = 0;
   anticolision_timer2 = 0;
}

///Funciones del modulo de detecci'on de bajo voltaje (modulos comparador y voltaje referencia)
void on_off_voltaje(short on_off_voltaje_local)
/*Esta funci'on es para encender o apagar el modulo de voltaje de referencia, el comparador analogico
y la interrupcion del modulo comparador*/
{
   if(on_off_voltaje_local == 0)   //apagado del modulo
   {
      disable_interrupts(INT_COMP);//desabilitar interrupcion del comparador analogico
     setup_comparator(NC_NC_NC_NC);   //apagado del modulo comparador
      setup_vref(FALSE);   //apagado del modulo de voltaje de referencia
     //estado_comparador = 0;   //comparador apagado
   }
   else                     //encendido del modulo
   {
      setup_comparator(A3_VR_A2_VR);   //configuracion usando la referencia interna
      setup_vref (VREF_HIGH|14);   //voltaje de referencia en 2,26875v con 3.3v de Vdd
      //estado_comparador = 1;   //comparador apagado
     enable_interrupts(INT_COMP);//habilitar interrupcion del comparador analogico
   }
}

///Funciones de atencion al watchfog
void comprobacion_awake(void)
{
	int vtemp3 = 0;

   vtemp3 = restart_cause();
   if(vtemp3 == WDT_FROM_SLEEP)
      watchdog_awake = 1;//la causa de la salida del sleep es del watchdog
   else 
      watchdog_awake = 0;//fue otra la causa de la salida del sleep
   //vtemp3 = 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///BLOQUE DE INTERRUPCIONES

#INT_TIMER2
void  TIMER2_isr(void) 
{
   contador_pulsos = contador_pulsos + 1;   // //Linea de codigo de prueba
   //output_toggle(PIN_A0);               //Linea de codigo de prueba

      timer2_on = 1;                  //Bandera que indica que se esta ejecutando la interrupcion
     if(modo == 1) 
	 {
       /* Motor de graficado de efectos */
      graficar(columna_graficado, buffer_graficado_on);                        //graficar lo que esta en el buffer
      
      /* seccion de preparaci'on del pr'oximo graficado*/
      if(columna_graficado < size_efecto)
         columna_graficado++;
      else if(columna_graficado >= size_efecto)
      {
         columna_graficado = 0;
        repeticiones_efecto++;   //indica que se lleg'o al final de la reproducc'on de un efecto
        
        if(repeticiones_efecto >= repeticiones_efectos_max)
       {
          if(carga_graficado_on == 0)
         {
            cambio_efecto = 1;      //indica que se lleg'o al final de una secuencia de repeticiones del mismo efecto
            repeticiones_efecto = 0;   //contador de numeros de repeticiones de efecto
         }
         else
            anticolision_timer2 = 1;   //Se activa la bandera de colision
       }
      }
      
       if(((cambio_efecto == 1)&&(estado_buffer1 == 4)&&(estado_buffer2 <= 2))||((cambio_efecto == 1)&&(estado_buffer1 <= 2)&&(estado_buffer2 == 4)))
      {
         cambio_efecto = 0;
         anticolision_timer2 = 0;
      }
	  
	  //clear_interrupt(int_timer2);
      timer2_on = 0;                              //Indico que  se acabo la interrupcion del timer2
	}
}

#INT_CCP1
void  CCP1_isr(void) 
{
   disable_interrupts(INT_TIMER2);              //Desabilita la interrupcion del timer2, dandole prioridad a CCP
	int Tg = 0;                            ///Variable que contiene el valor del tiempo de graficado
	int postscaler_timer2 = 1;               ///variable usada en la configuraci'on del timer 2
  
   if(estado_sleep == 1)
      estado_sleep = 0;   //Salida del modo sleep habilitado
   else if(estado_sleep == 0)//si se sale del modo sleep, el primer pulso CCP1 se desecha
   {
      if(lectura_on == 1)                  //variable de sincronizaci'on de la funci'on lectura_timer1 
         colision_CCP = 1;                //variable de sincronizacion de CCP1 con lectura_timer1 
      
      if(colision_CCP == 0)
         CCP1_on = 1;                           //Se indica que estamos en la interrupcion por CCP1
        
      if(modo == 1)  //BLOQUE DE CONFIGURACI'ON DEL TIMER2
      {
         Tg = Tg_ajustado_temp;       
         postscaler_timer2 = postscaler_timer2_temp;      
         setup_timer_2(T2_DIV_BY_4,Tg,postscaler_timer2);

         datos_ok = 0;                        ///Prepara el equipo para una nueva ronda de calculos
        
       /*Bloque para el primer graficado*/
      columna_graficado = 0; //Priemra columna
      graficar(columna_graficado, buffer_graficado_on); 
        
      }
      contador_pulsos = 0;         //variable de prueba
   }
enable_interrupts(INT_TIMER2);               //Antes de salir, habilita nuevamente la interrupcion del timer2
}

#INT_COMP
void comp_isr()
{
   //restart_wdt();
   
   if(C2OUT == 1)
   {
      apagado_completo = 1;   //bajo voltaje detectado
      modo = 2;
      estado_sleep = 2;
   }

   if(C1OUT == 1)   //Indicador que se oprimio el boton
   {
       short boton = 0;
      restart_wdt();
      delay_ms(1000);   //mecanismo antirebote
      restart_wdt();
      
      boton = C1OUT; //se lee la salida del comparador
      modo = 2;
      
      if((boton == 1)&&(apagado_completo == 0))
      {
        output_high(led1);
        delay_ms(1000);   
        output_low(led1);
        delay_ms(500);
        restart_wdt();
		
		 if(estado_sleep == 1)   //si estaba en modo ligth sleep
            estado_sleep = 2;   //cambio a modo deep sleep.
         else if(estado_sleep == 2)// si estaba en deep sleep
            estado_sleep = 1;   //cambio a modo ligth sleep
      }
   }
   
   delay_ms(10);   
   clear_interrupt(int_comp);
}

void main()
{
   set_tris_a(60);
   set_tris_b(11);
   //comprobacion_encendido();
   setup_wdt(WDT_2304MS);
   carga_inicial();
   on_off_voltaje(1);   //Encendido del modulo de medicion de estado de carga de la bateria
   on_off_timer1(1);
   enable_interrupts(GLOBAL);
    
   
   while(TRUE)
   {
      restart_wdt();
       
      /* BLOQUE DE CALCULOS EN SEGUNDO PLANO (Tg) */
       if((modo != 2)&&(apagado_completo == 0))
      {
         lectura_timer1();                           //Se lee el timer1 y se acumula su valor
             if(colision_CCP == 1)
             {
               anticolision();
                 lectura_timer1(); 
             }
			 			 
		   output_high(fase1);	// encender el sensor hall
      }
      
        /*Modo 2 SLEEP*/
        while(modo == 2)
       {
         switch (estado_sleep)
         {
            case 2:   //Modo DEEP SLEEP
                if(watchdog_awake != 1)
               {
                  on_off_timer1(0); //Desabilitar timer 1  modulo CCP1
				  output_low(fase1);	// apagar el sensor hall
                  preparacion_sleep();
               }
               watchdog_awake = 0;
               
               if(apagado_completo == 1)
                  {
                     on_off_voltaje(0);//apagado del modulo comparador, v.referencia y la interrupcion asociada
                     disable_interrupts(GLOBAL);
                  }
                  
               delay_us(1);      //punto de control y revision
                  sleep();
               delay_us(1);      //punto de control y revision
               comprobacion_awake();
               restart_wdt();
               
               if(( watchdog_awake == 1)&&(apagado_completo == 1))// si esta en modo de apagado completo por voltaje bajo, cada vez que despierte el PIC, enciende el efecto de bajo voltaje
                  efectos_simples();
                  
               //restart_wdt();
               break;
               
            case 1:   //MODO LIGTH SLEEP
               if(watchdog_awake != 1)
               {
				  output_low(fase1);	// apagar el sensor hall
                  on_off_timer1(1); //Encender timer 1  y modulo CCP1
                  preparacion_sleep();
               }
			   else
			   {
					output_high(fase1);	// encender el sensor hall
					delay_ms(1000);	//esperar 1 mS esperando un pulso
					output_low(fase1);	// apagar el sensor hall
			   }
               watchdog_awake = 0;
               delay_us(1);      //punto de control y revision
               sleep();   //Apagado luego de 1 s de inactividad.
               delay_us(1);      //punto de control y revision
               comprobacion_awake();
               //restart_wdt();
               break;
               
            case 0:   //MODO DE SALIDA DEL LIGTH SLEEP AL MODO NORMAL
               //restart_wdt();//Resetear watchdog
               carga_inicial();
               modo = 0;
               break;
         }
      }   
      
      if(apagado_completo == 0)
         vtemp0 = verificar_ciclo();   //Se verifica el tiempo de la ultima vuelta y se guarda el estado en vtemp
      
     if((vtemp0 == 0)&&(apagado_completo == 0)) //Aqui comienza la administracion de los bloques de bajo consumo   
        {   
               modo = 0;
            
            if((Acum_Tim1 / Tcm) > Valmax_Tim1_uS)      //Punto de verificacion 2. Condicion que define que el equipo esta parado o moviendose muy por debajo del VpS m'inimo
            {
            /* En este punto se resetean todas las variables que tienen que ver con el conteo de tiempo y luego se puede establecer el modo de bajo o muy bajo consumo*/   
               reset_variables_tim1();
               contador_ciclo = 0;
           
            /* Bloque de preparaci'on del SLEEP en el modo 1 - ligth sleep- */
            estado_sleep = 1;
            modo = 2;
         }
               //primera_ejecucion = 1;               //Se activa nuevamente la primera_ejecucion
        }
      else if((vtemp0 == 1)&&(apagado_completo == 0))                  //Se habilita el modo de graficado
         modo = 1;
      else if(apagado_completo == 1)
      {
         modo = 2;
         estado_sleep = 2;
      }
       
        /* BLOQUE DE MODO 1 O MODO DE GRAFICADO*/
    if(((modo == 1)&&(datos_ok == 0)&&(apagado_completo == 0)))
     {
    /*  Sub bloque de calculo de Tg*/            
      Tg_sin_ajuste = (Acum_Tim1_uS / vector_max);  
     
    if((Tg_sin_ajuste >= Valmin_Tim2)&&(Tg_sin_ajuste <= 1023))
			{
				prescaler_timer2_temp = 4;
				postscaler_timer2_temp = 1;
				Tg_ajustado_temp = calculo_tg();
				//indice_timer2 = 1;
			}
		else if((Tg_sin_ajuste >= 1024)&&(Tg_sin_ajuste <= 2047))
			{
				prescaler_timer2_temp = 4;
				postscaler_timer2_temp = 2;
				Tg_ajustado_temp = calculo_tg();
				//indice_timer2 = 2;
			}
		else if((Tg_sin_ajuste >= 2048)&&(Tg_sin_ajuste <= 3071))
			{
				prescaler_timer2_temp = 4;
				postscaler_timer2_temp = 3;
				Tg_ajustado_temp = calculo_tg();
				//indice_timer2 = 3;
			}
		else if((Tg_sin_ajuste >= 3072)&&(Tg_sin_ajuste <= 4095))
			{
				prescaler_timer2_temp = 4;
				postscaler_timer2_temp = 4;
				Tg_ajustado_temp = calculo_tg();
				//indice_timer2 = 4;
			}
		else if((Tg_sin_ajuste >= 4096)&&(Tg_sin_ajuste <= 5119))
			{
				prescaler_timer2_temp = 4;
				postscaler_timer2_temp = 5;
				Tg_ajustado_temp = calculo_tg();
				//indice_timer2 = 5;
			}
		else if((Tg_sin_ajuste >= 5120)&&(Tg_sin_ajuste <= 7168))
			{
				prescaler_timer2_temp = 4;
				postscaler_timer2_temp = 7;
				Tg_ajustado_temp = calculo_tg();
				//indice_timer2 = 6;
			}
		else if((Tg_sin_ajuste >= 7168)&&(Tg_sin_ajuste <= (Valmax_Tim2 - 1)))
			{
				prescaler_timer2_temp = 4;
				postscaler_timer2_temp = 14;
				Tg_ajustado_temp = calculo_tg();
				//indice_timer2 = 7;
			}
       
     datos_ok = 1;
	 
		 /* Sub bloque de precarga del proximo graficado*/
		if(cambio_efecto == 1)
		{
	         carga_graficado_on = 1;   //bandera que indica que se esta ejecutando el bloque de carga y graficado
	         
	         if((estado_buffer1 == 4)&&(estado_buffer2 == 3))
	         {
	            /*Seccin de graficado*/
	            buffer_graficado_on = 1;
	            cambio_efecto = 0;
	            estado_buffer2 = 4;
	            estado_buffer1 = 0;
	            size_efecto = (size_efectos[num_efecto] - 1);
	         
	            /*Seccin de carga */
	            seccion_carga();
	         }
	         else if((estado_buffer1 == 3)&&(estado_buffer2 == 4))
	         {
	            /*Seccin de graficado*/
	            buffer_graficado_on = 0;
	            cambio_efecto = 0;
	            estado_buffer1 = 4;
	            estado_buffer2 = 0;
	            size_efecto = (size_efectos[num_efecto] - 1);
	         
	            ///*Seccin de carga */
	            seccion_carga();
	         }
	         
	         if(anticolision_timer2 == 1)
	         {
	            cambio_efecto = 1;      //indica que se lleg'o al final de una secuencia de repeticiones del mismo efecto
	            repeticiones_efecto = 0;   //contador de numeros de repeticiones de efecto
	         }
			 
	         carga_graficado_on = 0;   
		}
     } 
   }
}

////////////////////////////////////////////////////////////////////////////

